#pragma once
#include "Sem.hpp"
#include <unistd.h>
#include <vector>
#include "Mutex.hpp"
#include <iostream>
#include <string>

namespace RingBufferModule
{
    using namespace LockModule;
    using namespace SemModule;

    static int number = 0;
    template <class T>
    class Ringbuffer
    {
    public:
        Ringbuffer(int cap)
            : _data(0),
              _space(cap),
              _ringbuffer(cap),
              _space_step(0),
              _data_step(0)
        {
            _name = "thread-" + std::to_string(number++);
        }
        std::string Name() {return _name;}
        // 生产者生产数据
        void Equeue(T &data)
        {
            // P(空间)
            _space.P();
            {
                LockGuard lock(_mutex);
                _ringbuffer[_space_step] = data;
                _space_step = (_space_step + 1) % _ringbuffer.size();
            }
            _data.V();
            // V(数据)
        }

        // 消费者消费数据
        void Pop(T *data)
        {
            // P数据
            _data.P();
            {
                LockGuard lock(_mutex);
                *data = _ringbuffer[_data_step];
                _data_step = (_data_step + 1) % _ringbuffer.size();
            }
            _space.V();
            // V空间
        }
        ~Ringbuffer() {}

    private:
        std::string _name;
        std::vector<T> _ringbuffer;
        int _space_step;
        int _data_step;
        Sem _data;
        Sem _space;
        Mutex _mutex;
    };
}
